<?php

namespace app\modules\backend\controllers;

use app\models\cacheModel\AdminRoleModel as AdminRoleCacheModel;
use app\models\tableModel\AdminAuthModel;
use app\models\tableModel\AdminRoleModel as AdminRoleDBModel;
use app\service\tool\UtilsService;
use yii\console\Exception as consoleException;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;

/**
 * 后台权限管理
 */
class AdminAuthController extends BaseController
{

    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        return [
            'verbs' => [ // 请求方式
                'class' => VerbFilter::className(),
                'actions' => [
                    ### 页面
                    'index-page' => ['GET'],
                    ### 接口
                    'setting' => ['GET'],
                    'list' => ['GET'],
                    'reload' => ['GET', 'POST'],
                    'disabled' => ['POST'],
                    'open' => ['POST'],
                    'save-auth' => ['POST'],
                    'rename' => ['POST']
                ],
            ]
        ];
    }


    /**
     * 列表页面
     * @return mixed
     */
    public function actionIndexPage()
    {

        return $this->render('index', []);
    }


    /**
     * 获取设置
     *  ` PS: 获取某些设置(如：状态列表等)以供前端使用
     * @return mixed
     */
    public function actionSetting()
    {

        // 类型 - 一般为首页[index]、表单[form]
        $type = $this->post('type');
        // 模型
        $model = AdminAuthModel::loadModel();
        return $this->jsonSuccess('成功', [
            'default_status' => $model::getStatOpen(), // 默认选中状态
            'status_list' => $model::getStatList(), // 状态文本列表值
            'sort_min' => $model::getSortMin(), // 最小排序值
            'sort_max' => $model::getSortMax(), // 最大排序值
        ]);
    }

    /**
     * 列表
     * @return mixed
     */
    public function actionList()
    {

        // 及时判断 - 如果角色信息不存在
        $roleId = $this->get('roleId');
        // 是否超管
        $isSuper = AdminRoleDbModel::isSuper($roleId);

        ### 获取下当前可用的所有角色
        $roleModel = AdminRoleDBModel::loadModel();
        // 角色列表
        $roleList = $roleModel->loadWhere([
            'status' => $roleModel::getStatusOpen()
        ])->getPaginate(1, 200, 'id, name, auth');
        $roleList = array_column($roleList->getList(), null, 'id');

        ### 加载已获取的权限
        $search = $this->get('search');
        $find = [];
        if (!empty($search['status'])) {
            $find[] =['=', 'status', $search['status']];
        }
        if (!empty($search['name'])) {
            $find[] =['LIKE', 'name', $search['name']];
        }
        $model = AdminAuthModel::loadModel();

        // 角色的权限存在
        $haveAuth = [];
        $haveIdList = [];
        // 有角色权限 && 非超管
        if (!empty($roleList[$roleId]['auth']) || $isSuper) {

            // 取出[已有父级]编号列表
            $haveParentList = array_unique(array_column(
                $roleList[$roleId]['auth'], 'parent_id'
            ));
            // 取出[已有子集]编号列表
            $haveIdList = $isSuper ? [] : array_unique(array_column(
                $roleList[$roleId]['auth'], 'id'
            ));
            // 只有非超管才过滤菜单
            $haveAuth = $model->loadWhere($isSuper ? [] : [
                'AND',
                ['IN', 'id', $haveIdList]
            ])->getPaginate(null, array_merge([
                'AND',
                ['=', 'parent_id', '0'],
                $isSuper ? [] : ['IN', 'id', $haveParentList]
            ], $find));
        }

        ### 加载未获取的权限
        $model = AdminAuthModel::loadModel();
        // 获取全部二级路由信息
        $stageList = [];
        // 超管拥有全部权限
        if (!$isSuper) $stageList = $model::find()->select('parent_id')->where(array_merge([
            'AND',
            ['<>', 'parent_id', '0'],
            ['NOT IN', 'id', $haveIdList]
        ], $find))->groupBy('parent_id')->asArray()->all();

        // 取出上级编号列表
        $idList = array_unique(array_column($stageList, 'parent_id'));

        $haveNotAuth = $model->loadWhere(array_merge([
            'AND',
            ['NOT IN', 'id', $haveIdList]
        ], $find))->getPaginate(null, [
            'AND',
            ['IN', 'id', $isSuper ? -100 : $idList]
        ]);

        return $this->jsonSuccess('成功', [
            'haveAuth' => $haveAuth ? $haveAuth->getList() : [],
            'haveNotAuth' => $haveNotAuth ? $haveNotAuth->getList() : [],
            'roleList' => $roleList
        ]);
    }

    /**
     * 重新加权限列表
     * @return mixed
     */
    public function actionReload()
    {

        // **** 1. 先加载下最新的路由文件信息 ****
        // 获取下全部的路由信息
        $model = AdminAuthModel::loadModel();
        // 加载模块、控制器、方法
        $model->loadModules()->loadControllers()->loadActions();
        // 如果有错误
        if ($model->hasErrors()) {

            $error = UtilsService::getModelError($model->errors);
            return $this->jsonFail($error['msg'], $error['code'], [
                'error_hint' => $error['msg']
            ]);
        }


        // **** 2. 更新控制器、方法到数据库 ****
        // 更新下路由权限信息[controller] - 以文件为基准
        if (!$model->updateController()) {

            $error = UtilsService::getModelError($model->errors);
            return $this->jsonFail($error['msg'], $error['code'], [
                'error_hint' => $error['error_hint'],
            ]);
        }

        // 更新下路由权限信息[action] - 以文件为基准
        if (!$model->updateAction()) {

            $err = UtilsService::getModelError($model->errors);
            return $this->jsonFail($err['msg'], $err['code'], [
                'error_hint' => $err['msg']
            ]);
        }

        // 返回下列表
        return $this->actionList();
    }

    /**
     * 禁用条目
     * @param array $idList 数据条目|多条数组格式，如：[1,2,3]
     * @return mixed
     */
    public function actionDisabled()
    {

        $idList = $this->post('idList');

        // 不是数组塑造下 为了构成100%的数组
        if (!empty($idList) && !is_array($idList)) $idList = explode(',', $idList);

        // 看获取的编号列表是否合法
        if (empty($idList) || count($idList) <= 0) {

            return $this->jsonFail('请选择一个条目', 400, [
                'error_hint' => '未传输任何编号',
                'errorCode' => 400
            ]);
        }

        // 检测多选条目
        $maxIdCount = $this->getMaxIdCount();
        if (count($idList) > intval($maxIdCount)) {
            return $this->jsonFail('每次最多选择操作' . $maxIdCount . '条数据', 400);
        }

        // ********** 1、先改变自身 **********
        // 条件
        $condition = ['AND', ['IN', 'id', $idList]];
        // 修改的字段
        $field = ['status' => AdminAuthModel::getStatDisabled()];
        // 是否操作成功 - 错误一般记录到[log]日志
        if (!AdminAuthModel::updateField($condition, $field)) {


            $error = UtilsService::getModelError(AdminAuthModel::getStaticErrors());
            // 将返回数据库级错误，暂不返回 会在日志中记录
            return $this->jsonFail($error['msg'], $error['column'] == 'unknown' ? 500 : 400);
        }

        // ********** 2、变其子集 **********
        // 条件
        $condition = ['AND', ['IN', 'parent_id', $idList]];
        // 也要更新到下面全部的禁用
        if (!AdminAuthModel::updateField($condition, $field)) {

            $error = UtilsService::getModelError(AdminAuthModel::getStaticErrors());
            // 将返回数据库级错误，暂不返回 会在日志中记录
            return $this->jsonFail($error['msg'], $error['column'] == 'unknown' ? 500 : 400);
        }

        return $this->jsonSuccess('成功');
    }

    /**
     * 开启条目
     * @param array $idList 数据条目|多条数组格式，如：[1,2,3]
     * @return mixed
     */
    public function actionOpen()
    {

        $idList = $this->post('idList');

        // 不是数组塑造下 为了构成100%的数组
        if (!empty($idList) && !is_array($idList)) $idList = explode(',', $idList);

        // 看获取的编号列表是否合法
        if (empty($idList) || count($idList) <= 0) {

            return $this->jsonFail('请选择一个条目', 400, [
                'error_hint' => '未传输任何编号',
                'errorCode' => 400
            ]);
        }

        // 检测多选条目
        $maxIdCount = $this->getMaxIdCount();
        if (count($idList) > intval($maxIdCount)) {
            return $this->jsonFail('每次最多选择操作' . $maxIdCount . '条数据', 400);
        }

        // 条件
        $condition = ['AND', ['IN', 'id', $idList]];
        // 修改的字段
        $field = ['status' => AdminAuthModel::getStatOpen()];
        // 是否操作成功 - 错误一般记录到[log]日志
        if (!AdminAuthModel::updateField($condition, $field)) {

            $error = UtilsService::getModelError(AdminAuthModel::getStaticErrors());
            // 将返回数据库级错误，暂不返回 会在日志中记录
            return $this->jsonFail($error['msg'], $error['column'] == 'unknown' ? 500 : 400);
        }

        // ********** 2、变其子集 **********
        // 条件
        $condition = ['AND', ['IN', 'parent_id', $idList]];
        // 也要更新到下面全部
        if (!AdminAuthModel::updateField($condition, $field)) {

            $error = UtilsService::getModelError(AdminAuthModel::getStaticErrors());
            // 将返回数据库级错误，暂不返回 会在日志中记录
            return $this->jsonFail($error['msg'], $error['column'] == 'unknown' ? 500 : 400);
        }

        return $this->jsonSuccess('成功');
    }

    /**
     * 重命名
     * @param array $idList 数据条目|多条数组格式，如：[1,2,3]
     * @param string $name 新名称
     * @return mixed
     */
    public function actionRename()
    {

        $idList = $this->post('idList');

        // 不是数组塑造下 为了构成100%的数组
        if (!empty($idList) && !is_array($idList)) $idList = explode(',', $idList);
        // 看获取的编号列表是否合法
        if (empty($idList) || count($idList) <= 0) {

            return $this->jsonFail('请选择一个条目', 400, [
                'error_hint' => '未传输任何编号',
                'errorCode' => 400
            ]);
        }
        // 检测多选条目
        $maxIdCount = $this->getMaxIdCount();
        if (count($idList) > intval($maxIdCount)) {
            return $this->jsonFail('每次最多选择操作' . $maxIdCount . '条数据', 400);
        }

        // 名称
        $name = $this->post('name', 'string');
        if(empty($name)) {

            return $this->jsonFail('请输入正确的名称', 400, [
                'error_hint' => '未填写名称',
                'errorCode' => 400
            ]);
        }


        // 条件
        $condition = ['AND', ['IN', 'id', $idList]];
        // 修改的字段
        $field = ['name' => $name];
        // 是否操作成功 - 错误一般记录到[log]日志
        if (!AdminAuthModel::updateField($condition, $field)) {

            $error = UtilsService::getModelError(AdminAuthModel::getStaticErrors());
            // 将返回数据库级错误，暂不返回 会在日志中记录
            return $this->jsonFail($error['msg'], $error['column'] == 'unknown' ? 500 : 400);
        }

        return $this->jsonSuccess('成功');
    }

    /**
     * 保存角色权限
     * @return \yii\console\Response|\yii\web\Response
     */
    public function actionSaveAuth()
    {

        ### 角色操作
        // 获取角色编号
        $roleId = $this->post('roleId');
        // 角色不是空
        if (empty($roleId)) {
            return $this->jsonFail('请选择角色', 404, [
                'error_hint' => '未传输角色编号',
                'errorCode' => 400
            ]);
        }

        // 数据库角色信息
        $roleDetail = AdminRoleCacheModel::loadModelDb($roleId);
        if (!$roleDetail) {
            return $this->jsonFail('请选择角色', 404, [
                'error_hint' => '角色未找到',
                'errorCode' => 400
            ]);
        }
        // 数据库实例
        $dbInstance = $roleDetail->getDbInstance();
        if ($roleDetail->getAttribute('status') != $dbInstance::getStatusOpen()) {
            return $this->jsonFail('角色已禁用', 404, [
                'error_hint' => '角色已禁用',
                'errorCode' => 400
            ]);
        }


        ### 获取加载下权限操作
        // 权限编号获取
        $authIdList = $this->post('authId');
        $authIdList = empty($authIdList) ? [] : $authIdList;
        // 基础条件
        $condition = [
            'AND',
            ['<>', 'parent_id', '0'],
            ['=', 'status', AdminAuthModel::getStatOpen()],
        ];
        // 如果非超管角色 则进行菜单的过滤
        if (!$dbInstance::isSuper($roleId)) $condition = array_merge($condition, [
            ['IN', 'id', $authIdList]
        ]);
        // 权限模块
        $authModel = AdminAuthModel::find();
        // 数据
        $authList = $authModel->where($condition)->select([
            'id', 'name', 'route', 'parent_id', 'url'
        ])->asArray()->all();


        ### 角色保存操作
        // 更新角色权限
        $roleDetail->setAttributes(['auth' => $authList]);
        // 保存角色权限
        if (!$roleDetail->save()) {
            $error = UtilsService::getModelError($roleDetail->errors);
            return $this->jsonFail($error['msg'], $error['code']);
        }

        return $this->jsonSuccess('成功');
    }
}
